/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.afollestad.materialdialogs.utils;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;
import ohos.app.Context;
import ohos.interwork.utils.ParcelableEx;
import ohos.utils.Parcel;
import ohos.utils.ParcelException;

public class UiUtil extends ComponentContainer {
    private static final String TAG = UiUtil.class.getSimpleName();
    private Context mContext;

    public UiUtil(Context context) {
        super(context);
        mContext = context;
    }

    public final ShapeElement getShapeElement(int shape, int color, float radius) {
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setShape(shape);
        shapeElement.setRgbColor(RgbColor.fromArgbInt(ResUtil.getColor(mContext, color)));
        shapeElement.setCornerRadius(radius);
        return shapeElement;
    }

    public final Element getStateElement(int[] states, ShapeElement shapeElement) {
        StateElement stateElement = new StateElement();
        stateElement.addState(states, shapeElement);
        return stateElement;
    }

    public static <E extends Component> E getComponent(Component root, int id) {
        if (root == null) {
            return null;
        }
        try {
            return (E) root.findComponentById(id);
        } catch (ClassCastException ex) {
            throw ex;
        }
    }

    /**
     * Ask one of the children of this view to measure itself, taking into account both the MeasureSpec requirements for this view and its padding.
     *
     * @param component         The child to measure
     * @param widthMeasureSpec  The width requirements for this view
     * @param heightMeasureSpec The height requirements for this view
     */
    public void measureChild(Component component, int widthMeasureSpec, int heightMeasureSpec) {
        final LayoutConfig layoutConfig = component.getLayoutConfig();
        int measuredWidth = getChildMeasuredWidthHeight(widthMeasureSpec, layoutConfig.getMarginLeft() + layoutConfig.getMarginRight(), layoutConfig.width);
        int measuredHeight = getChildMeasuredWidthHeight(heightMeasureSpec, layoutConfig.getMarginLeft() + layoutConfig.getMarginRight(), layoutConfig.height);
        measure(measuredWidth, measuredHeight);
    }

    /**
     * This method figures out the right MeasureSpec for one dimension (height or width) of one child view.
     *
     * @param widthHeightSpec The requirements for this view
     * @param padding         The padding of this view for the current dimension and margins, if applicable
     * @param childDimension  How big the child wants to be in the current dimension
     * @return a MeasureSpec integer for the child
     */
    private int getChildMeasuredWidthHeight(int widthHeightSpec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(widthHeightSpec);
        int specSize = MeasureSpec.getSize(widthHeightSpec);
        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
            // Parent has imposed an exact size on us
            case MeasureSpec.PRECISE:
                if (childDimension >= 0) {
                    resultSize = childDimension;
                    resultMode = MeasureSpec.PRECISE;
                } else if (childDimension == LayoutConfig.MATCH_PARENT) {
                    // Child wants to be our size. So be it.
                    resultSize = size;
                    resultMode = MeasureSpec.PRECISE;
                } else if (childDimension == LayoutConfig.MATCH_CONTENT) {
                    // Child wants to determine its own size. It can't be
                    // bigger than us.
                    resultSize = size;
                    resultMode = MeasureSpec.NOT_EXCEED;
                }
                break;

            // Parent has imposed a maximum size on us
            case MeasureSpec.NOT_EXCEED:
                if (childDimension >= 0) {
                    // Child wants a specific size... so be it
                    resultSize = childDimension;
                    resultMode = MeasureSpec.PRECISE;
                } else if (childDimension == LayoutConfig.MATCH_PARENT) {
                    // Child wants to be our size, but our size is not fixed.
                    // Constrain child to not be bigger than us.
                    resultSize = size;
                    resultMode = MeasureSpec.NOT_EXCEED;
                } else if (childDimension == LayoutConfig.MATCH_CONTENT) {
                    // Child wants to determine its own size. It can't be
                    // bigger than us.
                    resultSize = size;
                    resultMode = MeasureSpec.NOT_EXCEED;
                }
                break;

            // Parent asked to see how big we want to be
            case MeasureSpec.UNCONSTRAINT:
                if (childDimension >= 0) {
                    // Child wants a specific size... let him have it
                    resultSize = childDimension;
                    resultMode = MeasureSpec.PRECISE;
                } else if (childDimension == LayoutConfig.MATCH_PARENT) {
                    // Child wants to be our size... find out how big it should
                    // be
                    resultSize = size;
                    resultMode = MeasureSpec.UNCONSTRAINT;
                } else if (childDimension == LayoutConfig.MATCH_CONTENT) {
                    // Child wants to determine its own size.... find out how
                    // big it should be
                    resultSize = size;
                    resultMode = MeasureSpec.UNCONSTRAINT;
                }
                break;
        }
        //noinspection ResourceType
        return resultSize + resultMode;
    }

    /**
     * This is called to find out how big a view should be. The parent supplies constraint information in the width and height parameters.
     *
     * @param widthMeasureSpec  Horizontal space requirements as imposed by the parent
     * @param heightMeasureSpec Vertical space requirements as imposed by the parent
     */
    public void measure(int widthMeasureSpec, int heightMeasureSpec) {
        Insets insets = new Insets(0, 0, 0, 0);
        int oWidth = insets.left + insets.right;
        int oHeight = insets.top + insets.bottom;
        widthMeasureSpec = widthMeasureSpec + oWidth;
        heightMeasureSpec = heightMeasureSpec + oHeight;
    }

    private static class Insets implements ParcelableEx {
        final int left;
        final int top;
        final int right;
        final int bottom;

        private Insets(int left, int top, int right, int bottom) {
            this.left = left;
            this.top = top;
            this.right = right;
            this.bottom = bottom;
        }

        @Override
        public void marshallingEx(Parcel out) throws ParcelException {
            out.writeInt(left);
            out.writeInt(top);
            out.writeInt(right);
            out.writeInt(bottom);
        }

        @Override
        public void unmarshallingEx(Parcel in) throws ParcelException {

        }
    }
}
